#pragma once

#include "bsp/board_config.h"
#include "protocol.h"

//#define MAGIC_APP_BOOT_OK			0x11223344
#define MAGIC_DUAL_BANK_UPGRADE			0x55667788

#define MAGIC_ENTER_BOOT   0x12344321
#define MAGIC_APP_READY    0xa5667667
#define MAGIC_APP_BOOT_OK  0x5aa5abcd

#define PART_BOOT			CONFIG_PART_BOOT
#define PART_APP			CONFIG_PART_APP
#define PART_NAME			CONFIG_PART_NAME

#define CONFIG_IAP_CRC32		1

#define CONFIG_TRY_BOOT_DELAY  100

typedef enum {
	IAP_APP,
	IAP_ENTER,
	IAP_BEGIN,
	IAP_WRITE,
	IAP_CHECK,
	IAP_BOOT,
	IAP_TIMEOUT = 0xFF,
} iap_state_t;

typedef struct {
	u32 length;
	u32 checksum;
	u32 magic;
	u32 address;
} iap_info_t;

typedef struct {
	iap_info_t info;
	u32 dual_addr;
	u32 dual_len;
	u32 dual_checksum;
}dual_iap_info_t;

typedef struct {
	iap_state_t state;
	u16 iap_ticks;
	u32 ticks;
	int run_app_delay;
	u8  page[CONFIG_IAP_PAGE_SIZE];
	u32 address;
	u16 length;
	u32 write_position;
} iap_t;

extern iap_t iap;

u32 iap_checksum_init(void);
u32 iap_checksum_finish(u32 checksum);
u32 iap_checksum_update(u32 checksum, const u8 *buff, u32 length);
u32 iap_checksum(u32 addr, u32 length);

u32 iap_max_size(void);
u32 iap_last_page(void);

void iap_write_begin(void);
bool iap_write_check(u32 length, u32 checksum);
bool iap_write_end(u32 length, u32 checksum, u32 magic);
bool iap_flush(u32 length);
bool iap_write(const u8 *buff, u16 length);
bool iap_write_u32(u32 value);
bool iap_boot(bool normal);
bool iap_fmc_upgrade(void);
bool iap_spi_upgrade(void);
void iap_spi_test_write(void);
void iap_upgrade_bootloader(void);
void iap_process_pack(can_pack_t *pack);
void iap_running_app(void);
void iap_run_app_delay(u32 ticks);
void iap_cancel_runapp(void);